package com.cartoonrabbit.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cartoonrabbit.consts.NotificationAPIURL;
import com.cartoonrabbit.consts.TradeStatus;
import com.cartoonrabbit.consts.WxAPIURL;
import com.cartoonrabbit.pojo.InviteRecord;
import com.cartoonrabbit.pojo.RechargeOrder;
import com.cartoonrabbit.mapper.RechargeOrderMapper;
import com.cartoonrabbit.pojo.User;
import com.cartoonrabbit.pojo.WithdrawOrder;
import com.cartoonrabbit.service.IInviteRecordService;
import com.cartoonrabbit.service.IRechargeOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cartoonrabbit.service.IUserService;
import com.cartoonrabbit.service.IWxPayService;
import com.cartoonrabbit.vo.RespBean;
import com.cartoonrabbit.vo.RespPageBean;
import com.cartoonrabbit.wxapp.properties.WxAppInfoProperties;
import com.cartoonrabbit.wxapp.properties.WxAppPayProperties;
import com.cartoonrabbit.wxapp.utils.PrimaryKeyUtils;
import com.cartoonrabbit.wxapp.utils.SignUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author LiuTeng
 * @since 2023-01-09
 */
@Service
public class RechargeOrderServiceImpl extends ServiceImpl<RechargeOrderMapper, RechargeOrder> implements IRechargeOrderService {

    @Autowired
    private WxAppPayProperties wxAppPayProperties;
    @Autowired
    private WxAppInfoProperties wxAppInfoProperties;

    @Autowired
    private CloseableHttpClient closeableHttpClient;

    @Autowired
    private SignUtils signUtils;

    @Autowired
    private IWxPayService wxPayService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IInviteRecordService inviteRecordService;

    @Override
    public RespBean doPrePay(Long money, String openId) throws Exception {

// 生成订单
        RechargeOrder order = handleOrderInfo("卡通图制作次数充值",money, openId);
        if (order==null){
            return RespBean.fail("服务器异常，订单信息生成失败");
        }
        // 调用JSAPI接口获取预支付id
        HttpPost httpPost = new HttpPost(WxAPIURL.NATIVE);
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type","application/json; charset=utf-8");

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode rootNode = objectMapper.createObjectNode();
        rootNode.put("mchid",wxAppPayProperties.getMchId())
                .put("appid", wxAppInfoProperties.getAppId())
                .put("description", order.getDescription())
                .put("notify_url", NotificationAPIURL.ACCOUNT_RECHARGE)
                .put("out_trade_no", order.getOrderId())
                .put("time_expire",(order.getTimeExpire()
                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss+08:00")))
                        .replace(" ","T"));// 过期时间
        // 支付金额
        rootNode.putObject("amount")
                .put("total", order.getTradeMoney().intValue());
        rootNode.putObject("payer")
                .put("openid", order.getOpenId());

        objectMapper.writeValue(bos, rootNode);

        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
        CloseableHttpResponse response = closeableHttpClient.execute(httpPost);

        String bodyAsString = EntityUtils.toString(response.getEntity());
        // 获取预支付id
        JSONObject resObj = JSONUtil.parseObj(bodyAsString);
        String prepayId=null;
        if (resObj.getObj("code")!=null){
            return RespBean.fail("请求支付异常");
        }else {
            prepayId=resObj.getStr("prepay_id");
            // 获取成功后处理余额明细
            order.setPrepayId(prepayId);
            // 保存订单
            save(order);
        }

        long times = System.currentTimeMillis() / 1000;
        String randomString = RandomUtil.randomString(32);
        String timeStamp=String.valueOf(times);
        String nonceStr=randomString;
        String pacKage="prepay_id="+prepayId;
        String signStr = signUtils.getSign(wxAppInfoProperties.getAppId(), times, randomString, pacKage);
        String paySign=signStr;
        //预支付id，时间戳，随机字符串，支付签名，签名类型
        Map<String,String> resultMap=new HashMap<>();
        resultMap.put("timeStamp",timeStamp);
        resultMap.put("nonceStr",nonceStr);
        resultMap.put("package",pacKage);
        resultMap.put("signType","RSA");
        resultMap.put("paySign",paySign);
        resultMap.put("orderId",order.getOrderId());
        return RespBean.success("SUCCESS",resultMap);
    }

    @Override
    @Transactional
    public RespBean doNotify(String orderId, Integer status, String openId) {
        if (status == 0) {
            // 删除订单
            removeById(orderId);
            return RespBean.success("SUCCESS", null);
        } else {
            // 查单
//调用微信支付查单接口
            String orderStatusByString = null;
            User returnUser=null;
            try {
                orderStatusByString = wxPayService.queryOrderStatusByString(orderId);
            } catch (IOException e) {
                throw new RuntimeException("请求查单接口异常");
            }

            JSONObject entries = JSONUtil.parseObj(orderStatusByString);
            //获取微信支付端的状态
            Object tradeState = entries.getStr("trade_state");
            if (tradeState != null && tradeState.equals("SUCCESS")) {
                // 更新订单状态
                RechargeOrder order = getById(orderId);
                order.setOrderId(orderId);
                order.setTradeStatus(TradeStatus.SUCCESS);
                order.setTradeId(entries.getStr("transaction_id"));
                order.setTradeContent(orderStatusByString);
                updateById(order);
                // todo 更改用户制作次数
                User user = userService.getById(openId);
                User updateUser = new User();
                updateUser.setOpenId(openId);
                updateUser.setProductTimes(order.getProductTimes() + user.getProductTimes());
                user.setProductTimes(updateUser.getProductTimes());
                returnUser=user;
                userService.updateById(updateUser);
                // todo 提成计算
                InviteRecord inviteRecord = inviteRecordService.getOne(new QueryWrapper<InviteRecord>().eq("invited_openId", openId));
                if (!ObjectUtils.isEmpty(inviteRecord)){
                    // 返20%佣金
                    long yongjing = new Double(Math.ceil(order.getTradeMoney() * 0.2)).longValue();
                    inviteRecord.setAwardMoney(yongjing+inviteRecord.getAwardMoney());
                    inviteRecordService.updateById(inviteRecord);
                    // 获取佣金的用户余额增加
                    String inviteOpenid = inviteRecord.getInviteOpenid();
                    User inviteUser = userService.getById(inviteOpenid);
                    inviteUser.setBalance(inviteUser.getBalance()+yongjing);
                    // 次数加一
                    inviteUser.setProductTimes(inviteUser.getProductTimes()+1);
                    userService.updateById(inviteUser);
                }
            }
            return RespBean.success("SUCCESS",returnUser);
        }
    }

    @Override
    public RespBean getRechargeOrderList(Integer currentPage, Integer size, String name) {
        Page page=new Page(currentPage,size);
        Page<RechargeOrder> rechargeOrderPage=page(page,new QueryWrapper<RechargeOrder>().eq("open_id",name));
        RespPageBean respPageBean = new RespPageBean();
        respPageBean.setCurrentPage(rechargeOrderPage.getCurrent());
        respPageBean.setSize(rechargeOrderPage.getSize());
        respPageBean.setTotal(rechargeOrderPage.getTotal());
        respPageBean.setData(rechargeOrderPage.getRecords());
        return RespBean.success("SUCCESS",respPageBean);
    }

    private RechargeOrder handleOrderInfo(String description,Long money, String openId) {
        // 生成订单过期时间
        LocalDateTime time_expire = LocalDateTime.now().plusMinutes(10);
        RechargeOrder order = new RechargeOrder();
        order.setOrderId(PrimaryKeyUtils.getOrderNo());
        order.setOpenId(openId);
        order.setDescription(description);
        order.setTradeMoney(money);
        order.setTradeTime(LocalDateTime.now());
        order.setTradeStatus(TradeStatus.NOPAY);
        order.setTimeExpire(time_expire);
        if (money==50){
            order.setProductTimes(1);
        }else if (money==100){
            order.setProductTimes(4);
        }else if (money==200){
            order.setProductTimes(10);
        }else if (money==300){
            order.setProductTimes(20);
        }else if (money==500){
            order.setProductTimes(50);
        }else if (money==9900){
            order.setProductTimes(99999);
        }else {
            order.setProductTimes(0);
        }

        return order;
    }
}
